package com.vcc.channel.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.vcc.channel.base.channel.PhotonResult;
import com.vcc.channel.base.config.BaseConfig;
import com.vcc.channel.base.model.request.*;
import com.vcc.channel.base.model.response.*;
import com.vcc.channel.base.util.RsaUtil;
import com.vcc.channel.config.ChannelConfig;
import com.vcc.channel.service.service.PhotonService;
import com.vcc.core.constant.CardStatusEnum;
import com.vcc.core.constant.CardTypeEnum;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.HttpUtil;
import com.vcc.core.util.RedisCustomizeUtils;
import com.vcc.data.entity.CardType;
import com.vcc.data.entity.UserCard;
import com.vcc.service.service.CardOrderService;
import com.vcc.service.service.CardTypeService;
import com.vcc.service.service.UserCardService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service("PhotonPay")
public class PhotonServiceImpl implements PhotonService {

    private static Logger logger = LoggerFactory.getLogger(PhotonServiceImpl.class);

    @Resource
    public ChannelConfig channelConfig;
    @Resource
    private CardTypeService cardTypeService;
    @Resource
    private CardOrderService cardOrderService;
    @Resource
    private UserCardService userCardService;

    @Value("${spring.profiles.active:dev}")
    private String activeProfile;


    private BaseConfig getPhotonConfig() {
        return channelConfig.getPhoton();
    }

    private HashMap<String, String> getAuthHeader() {
        HashMap<String, String> header = HttpUtil.createHeader();
        header.put("Authorization", "basic " + Base64.encode(getPhotonConfig().getAppId() + "/" + getPhotonConfig().getAppSecret()));
        header.put("Content-Type", "application/json");
        return header;
    }

    private HashMap<String, String> getGetAptHeader() {
        HashMap<String, String> header = HttpUtil.createHeader();
        header.put("Content-Type", "application/json");
        header.put("X-PD-SIGN", RsaUtil.md5Sign(JSON.toJSONString(HttpUtil.createBody()), getPhotonConfig().getPrivateKey()));
        header.put("X-PD-TOKEN", getApiToken());
        return header;
    }

    private HashMap<String, String> getPostHeader(HashMap<String, Object> requestBody) {
        HashMap<String, String> header = HttpUtil.createHeader();
        header.put("Content-Type", "application/json");
        header.put("X-PD-SIGN", RsaUtil.md5Sign(JSON.toJSONString(requestBody), getPhotonConfig().getPrivateKey()));
        header.put("X-PD-TOKEN", getApiToken());
        return header;
    }


    private PhotonResult checkResponse(String response, Boolean hasException) {
        PhotonResult photonResult = JSONUtil.toBean(response, PhotonResult.class);
        if (photonResult.hasError() && hasException) {
            throw new ProgramException("请求失败: " + photonResult.getMsg());
        }
        return photonResult;
    }

    private String getApiToken() {
        if (RedisCustomizeUtils.hasKey("photon:api_token")) {
            return RedisCustomizeUtils.get("photon:api_token");
        }
        String response = "";
        try {
            response = HttpUtil.post(
                    getPhotonConfig().getUrl(getPhotonConfig().getGetTokenUrl()),
                    getAuthHeader(),
                    HttpUtil.createBody()
            );
        } catch (IORuntimeException e) {
            throw new ProgramException("请求Token失败，请检查网络");
        }
        PhotonResult result = checkResponse(response, true);
        JSONObject data = result.dataToEntity(JSONObject.class);
        String token = data.getString("token");
        if (StringUtils.isBlank(token)) {
            throw new ProgramException("获取token失败: " + result.getMsg());
        }
        RedisCustomizeUtils.set("photon:api_token", token, 50L, TimeUnit.MINUTES);
        return token;
    }

    @Override
    public Object openCard(HashMap<String, Object> requestParams) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("requestId", requestParams.get("requestId"));
        requestBody.put("cardType", "share");
        requestBody.put("cardholderId", requestParams.get("cardholderId"));
        requestBody.put("cardCurrency", "USD");
        requestBody.put("cardBin", requestParams.get("cardBin"));
        if (requestParams.get("type").equals(CardTypeEnum.NORMAL.getCode())) {
            if (activeProfile.equals("prod")) {
                requestBody.put("matrixAccount", "MI1952819651775836160");
                requestBody.put("memberId", "2025071887897303");
            }
            requestBody.put("transactionLimit", BigDecimal.ZERO);
        } else {
            requestBody.put("matrixAccount", requestParams.get("accountId"));
            requestBody.put("transactionLimit", requestParams.get("limit"));
        }
        requestBody.put("transactionLimitType", "limited");
        PhotonResult result = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getOpenCardUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (result.hasSuccess()) {
            JSONObject data = result.dataToEntity(JSONObject.class);
            switch (data.getString("status")) {
                case "failed": {
                    //开卡失败
                    cardOrderService.openCardComplete(
                            requestParams.get("requestId").toString(),
                            null,
                            null,
                            "FAIL"
                    );
                    break;
                }
                case "pending": {
                    logger.info("Photon openCard requestId: {} status: {}", requestParams.get("requestId"), data.getString("status"));
                    break;
                }
                case "succeed": {
                    CardType cardType = cardTypeService.getById(Long.valueOf(requestParams.get("cardTypeId").toString()));
                    JSONObject cardDetails = data.getJSONObject("cardDetail");
                    UserCard userCard = new UserCard();
                    userCard.setCardNumber(cardDetails.getString("cardNo"));
                    userCard.setCardGroupId(requestParams.containsKey("groupId") ? Long.valueOf(requestParams.get("groupId").toString()) : null);
                    userCard.setCardNumberLastFour(cardDetails.getString("cardNo").substring(cardDetails.getString("cardNo").length() - 4));
                    userCard.setVcc(cardDetails.getString("cvv"));
                    userCard.setExpiry("20" + cardDetails.getString("expirationDate").substring(3) + "-" + cardDetails.getString("expirationDate").substring(0, 2));
                    userCard.setRequestDate(new Date());
                    userCard.setOrderId(requestParams.get("requestId").toString());
                    userCard.setCardType(requestParams.get("type").toString());
                    userCard.setCardTypeId(Long.valueOf(requestParams.get("cardTypeId").toString()));
                    userCard.setUserId(Long.valueOf(requestParams.get("userId").toString()));
                    userCard.setChannelCardId(cardDetails.getString("cardId"));
                    userCard.setChannelCode(cardType.getChannelName());
                    userCard.setCurrencyCode(cardType.getCurrencyCode());
                    userCard.setCurrencyName(cardType.getCurrencyName());
                    userCard.setCardLabel(cardType.getCardLabel());
                    userCard.setUsableQuota(BigDecimal.valueOf(0));
                    userCard.setRemark(requestParams.containsKey("remark") ? requestParams.get("remark").toString() : "");
                    userCard.setCardStatus("ACTIVE");
                    userCard.setSumCount(0);
                    userCard.setSuccessCount(0);
                    userCard.setErrorCount(0);
                    userCard.setSumAmount(BigDecimal.valueOf(0));
                    userCard.setSuccessAmount(BigDecimal.valueOf(0));
                    userCard.setErrorAmount(BigDecimal.valueOf(0));
                    userCard.setCardholderId(Long.valueOf(requestParams.get("alCardholderId").toString()));
                    if (requestParams.get("type").equals(CardTypeEnum.SHARE.getCode())) {
                        userCard.setTransactionLimit((BigDecimal) requestParams.get("limit"));
                        userCard.setShareAccountId(Long.valueOf(requestParams.get("shareAccountId").toString()));
                    }
                    userCardService.save(userCard);
                    cardOrderService.openCardComplete(
                            requestParams.get("requestId").toString(),
                            userCard.getCardNumber(),
                            userCard.getId(),
                            "SUCCESS"
                    );
                    break;
                }
            }
            return true;
            //开卡成功
        } else {
            //开卡失败
            cardOrderService.openCardComplete(
                    requestParams.get("requestId").toString(),
                    null,
                    null,
                    "FAIL"
            );
            throw new ProgramException("开卡失败 ");
        }
    }

    @Override
    public Object openShareCard(HashMap<String, Object> requestParams) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("requestId", requestParams.get("requestId"));
        requestBody.put("cardType", "share");
        requestBody.put("cardholderId", requestParams.get("cardholderId"));
        requestBody.put("cardCurrency", "USD");
        requestBody.put("cardBin", requestParams.get("cardBin"));
        requestBody.put("matrixAccount", requestParams.get("accountId"));
        requestBody.put("transactionLimit", requestParams.get("limit"));
        requestBody.put("transactionLimitType", "limited");
        PhotonResult result = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getOpenCardUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (result.hasSuccess()) {
            JSONObject data = result.dataToEntity(JSONObject.class);
            switch (data.getString("status")) {
                case "failed": {
                    //开卡失败
                    cardOrderService.openShareCardComplete(
                            requestParams.get("requestId").toString(),
                            null,
                            null,
                            "FAIL"
                    );
                    break;
                }
                case "pending": {
                    logger.info("Photon openCard requestId: {} status: {}", requestParams.get("requestId"), data.getString("status"));
                    break;
                }
                case "succeed": {
                    CardType cardType = cardTypeService.getById(Long.valueOf(requestParams.get("cardTypeId").toString()));
                    JSONObject cardDetails = data.getJSONObject("cardDetail");
                    UserCard userCard = new UserCard();
                    userCard.setCardNumber(cardDetails.getString("cardNo"));
                    userCard.setCardGroupId(requestParams.containsKey("groupId") ? Long.valueOf(requestParams.get("groupId").toString()) : null);
                    userCard.setCardNumberLastFour(cardDetails.getString("cardNo").substring(cardDetails.getString("cardNo").length() - 4));
                    userCard.setVcc(cardDetails.getString("cvv"));
                    userCard.setExpiry("20" + cardDetails.getString("expirationDate").substring(3) + "-" + cardDetails.getString("expirationDate").substring(0, 2));
                    userCard.setRequestDate(new Date());
                    userCard.setOrderId(requestParams.get("requestId").toString());
                    userCard.setCardType(requestParams.get("type").toString());
                    userCard.setCardTypeId(Long.valueOf(requestParams.get("cardTypeId").toString()));
                    userCard.setUserId(Long.valueOf(requestParams.get("userId").toString()));
                    userCard.setChannelCardId(cardDetails.getString("cardId"));
                    userCard.setChannelCode(cardType.getChannelName());
                    userCard.setCurrencyCode(cardType.getCurrencyCode());
                    userCard.setCurrencyName(cardType.getCurrencyName());
                    userCard.setCardLabel(cardType.getCardLabel());
                    userCard.setUsableQuota((BigDecimal) requestParams.get("limit"));
                    userCard.setTransactionLimit((BigDecimal) requestParams.get("limit"));
                    userCard.setRemark(requestParams.containsKey("remark") ? requestParams.get("remark").toString() : "");
                    userCard.setCardStatus("ACTIVE");
                    userCard.setSumCount(0);
                    userCard.setSuccessCount(0);
                    userCard.setErrorCount(0);
                    userCard.setSumAmount(BigDecimal.valueOf(0));
                    userCard.setSuccessAmount(BigDecimal.valueOf(0));
                    userCard.setErrorAmount(BigDecimal.valueOf(0));
                    userCard.setCardholderId(Long.valueOf(requestParams.get("alCardholderId").toString()));
                    if (requestParams.get("type").equals(CardTypeEnum.SHARE.getCode())) {
                        userCard.setTransactionLimit((BigDecimal) requestParams.get("limit"));
                        userCard.setShareAccountId(Long.valueOf(requestParams.get("shareAccountId").toString()));
                    }
                    userCardService.save(userCard);
                    cardOrderService.openShareCardComplete(
                            requestParams.get("requestId").toString(),
                            userCard.getCardNumber(),
                            userCard.getId(),
                            "SUCCESS"
                    );
                    break;
                }
            }
            return true;
            //开卡成功
        } else {
            //开卡失败
            cardOrderService.openShareCardComplete(
                    requestParams.get("requestId").toString(),
                    null,
                    null,
                    "FAIL"
            );
            throw new ProgramException("开卡失败 ");
        }
    }

    @Override
    public Boolean recharge(CardRechargeDto cardRechargeDto) {
        String cardStatus = queryCardStatus(cardRechargeDto.getChannelCardId());
        if (!CardStatusEnum.ACTIVE.getCode().equals(cardStatus)) {
            cardOrderService.rechargeCardComplete(
                    cardRechargeDto.getRequestId(),
                    cardRechargeDto.getCardNumber(),
                    cardRechargeDto.getCardNumberId(),
                    "FAIL"
            );
            throw new ProgramException("卡状态异常，无法充值");
        }
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("requestId", cardRechargeDto.getRequestId());
        requestBody.put("cardId", cardRechargeDto.getChannelCardId());
        requestBody.put("transactionLimit", cardRechargeDto.getRechargeAmount());
        requestBody.put("transactionLimitType", "limited");
        requestBody.put("transactionLimitChangeType", "increase");
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getRechargeUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            BigDecimal availableTransactionLimit = data.getBigDecimal("availableTransactionLimit");
            userCardService.updateUsableQuotaByChannelCardId(
                    availableTransactionLimit,
                    cardRechargeDto.getChannelCardId()
            );
        }
        return cardOrderService.rechargeCardComplete(
                cardRechargeDto.getRequestId(),
                cardRechargeDto.getCardNumber(),
                cardRechargeDto.getCardNumberId(),
                photonResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public Boolean withdraw(CardWithdrawDto cardWithdrawDto) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("requestId", cardWithdrawDto.getRequestId());
        requestBody.put("cardId", cardWithdrawDto.getChannelCardId());
        requestBody.put("transactionLimit", cardWithdrawDto.getWithdrawAmount());
        requestBody.put("transactionLimitType", "limited");
        requestBody.put("transactionLimitChangeType", "decrease");
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getWithdrawUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            BigDecimal availableTransactionLimit = data.getBigDecimal("availableTransactionLimit");
            userCardService.updateUsableQuotaByChannelCardId(
                    availableTransactionLimit,
                    cardWithdrawDto.getChannelCardId()
            );
        }
        return cardOrderService.withdrawCardComplete(
                cardWithdrawDto.getRequestId(),
                cardWithdrawDto.getCardNumber(),
                cardWithdrawDto.getCardNumberId(),
                photonResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public Boolean cancelCard(CardCancelDto cardCancelDto) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("cardId", cardCancelDto.getChannelCardId());
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getCancelUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            userCardService.updateCardStatusByChannelCardId(
                    CardStatusEnum.CLOSE.getCode(),
                    cardCancelDto.getChannelCardId()
            );
        }
        return cardOrderService.closeCardComplete(
                cardCancelDto.getRequestId(),
                photonResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public Boolean blockCard(String channelCardId, String requestId) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("cardId", channelCardId);
        requestBody.put("requestId", requestId);
        requestBody.put("status", "freeze");
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getBlockUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        return cardOrderService.blockCardComplete(
                requestId,
                photonResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public Boolean unblockCard(String channelCardId, String requestId) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("cardId", channelCardId);
        requestBody.put("requestId", requestId);
        requestBody.put("status", "unfreeze");
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getUnBlockUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        return cardOrderService.unblockCardComplete(
                requestId,
                photonResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    @Override
    public PageVo<PageTransactionVo> pagingTransaction(Integer pageNumber, Integer pageSize, String channelCardId, String transactionType, String status, Date startTime, Date endTime) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("pageIndex", pageNumber);
        param.put("pageSize", pageSize);
        param.put("cardId", channelCardId);
        param.put("transactionType", transactionType);
        param.put("status", status);
        if (startTime != null) {
            param.put("createdAtStart", DateUtil.format(startTime, DatePattern.UTC_SIMPLE_PATTERN));
        }
        if (endTime != null) {
            param.put("createdAtEnd", DateUtil.format(endTime, DatePattern.UTC_SIMPLE_PATTERN));
        }
        PhotonResult photonResult = checkResponse(
                HttpUtil.get(
                        getPhotonConfig().getUrl(getPhotonConfig().getPagingTransactionUrl()),
                        param,
                        getGetAptHeader(),
                        HttpUtil.createBody()
                ),
                true
        );
        PageVo<PageTransactionVo> pageVo = new PageVo<>();
        pageVo.setPageNumber(photonResult.getPageIndex());
        pageVo.setPageSize(photonResult.getPageSize());
        pageVo.setTotal(Long.valueOf(photonResult.getTotal()));
        pageVo.setHasMore(Objects.equals(photonResult.getNumbers(), pageSize));
        pageVo.setData(
                photonResult.dataToListEntity(JSONObject.class).stream().map(it -> {
                    PageTransactionVo pageTransactionVo = new PageTransactionVo();
                    pageTransactionVo.setTransactionId(it.getString("transactionId"));
                    pageTransactionVo.setChannelCardId(it.getString("cardId"));
                    pageTransactionVo.setCardNumber(it.getString("cardNo"));
                    pageTransactionVo.setTransactionType(it.getString("transactionType"));
                    pageTransactionVo.setTransactionStatus(it.getString("status"));
                    pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
                    pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
                    pageTransactionVo.setTransactionDate(DateUtil.parse(it.getString("createdAt"), DatePattern.UTC_SIMPLE_PATTERN));
                    pageTransactionVo.setMerchantName(it.getString("merchantNameLocation"));
                    pageTransactionVo.setMcc(it.getString("mcc"));
                    pageTransactionVo.setMerchantCountry(it.getString("merchantLocation"));
                    pageTransactionVo.setRemark(it.getString("msg"));
                    pageTransactionVo.setBillingAmount(it.getBigDecimal("txnPrincipalChangeAmount"));
                    pageTransactionVo.setBillingCurrency(it.getString("txnPrincipalChangeCurrency"));
                    pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
                    pageTransactionVo.setFee(it.getBigDecimal("feeDeductionAmount"));
                    pageTransactionVo.setFeeCurrency(it.getString("feeDeductionCurrency"));
                    return pageTransactionVo;
                }).toList()
        );
        return pageVo;
    }

    @Override
    public PageVo<PageTransactionVo> pagingTransaction(Integer pageNumber, Integer pageSize, String transactionType, String status, Date startTime, Date endTime) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("pageIndex", pageNumber);
        param.put("pageSize", pageSize);
        param.put("transactionType", transactionType);
        param.put("status", status);
        if (startTime != null) {
            param.put("createdAtStart", DateUtil.format(startTime, DatePattern.UTC_SIMPLE_PATTERN));
        }
        if (endTime != null) {
            param.put("createdAtEnd", DateUtil.format(endTime, DatePattern.UTC_SIMPLE_PATTERN));
        }
        PhotonResult photonResult = checkResponse(
                HttpUtil.get(
                        getPhotonConfig().getUrl(getPhotonConfig().getPagingTransactionUrl()),
                        param,
                        getGetAptHeader(),
                        HttpUtil.createBody()
                ),
                true
        );
        PageVo<PageTransactionVo> pageVo = new PageVo<>();
        pageVo.setPageNumber(photonResult.getPageIndex());
        pageVo.setPageSize(photonResult.getPageSize());
        pageVo.setTotal(Long.valueOf(photonResult.getTotal()));
        pageVo.setHasMore(Objects.equals(photonResult.getNumbers(), pageSize));
        pageVo.setData(
                photonResult.dataToListEntity(JSONObject.class).stream().map(it -> {
                    PageTransactionVo pageTransactionVo = new PageTransactionVo();
                    pageTransactionVo.setTransactionId(it.getString("transactionId"));
                    pageTransactionVo.setChannelCardId(it.getString("cardId"));
                    pageTransactionVo.setCardNumber(it.getString("cardNo"));
                    pageTransactionVo.setTransactionType(it.getString("transactionType"));
                    pageTransactionVo.setTransactionStatus(it.getString("status"));
                    pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
                    pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
                    pageTransactionVo.setTransactionDate(DateUtil.parse(it.getString("createdAt"), DatePattern.UTC_SIMPLE_PATTERN));
                    pageTransactionVo.setMerchantName(it.getString("merchantNameLocation"));
                    pageTransactionVo.setMcc(it.getString("mcc"));
                    pageTransactionVo.setMerchantCountry(it.getString("merchantLocation"));
                    pageTransactionVo.setRemark(it.getString("msg"));
                    pageTransactionVo.setBillingAmount(it.getBigDecimal("txnPrincipalChangeAmount"));
                    pageTransactionVo.setBillingCurrency(it.getString("txnPrincipalChangeCurrency"));
                    pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
                    pageTransactionVo.setFee(it.getBigDecimal("feeDeductionAmount"));
                    pageTransactionVo.setFeeCurrency(it.getString("feeDeductionCurrency"));
                    return pageTransactionVo;
                }).toList()
        );
        return pageVo;
    }

    @Override
    public PageTransactionVo queryTransaction(String transactionId) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("transactionId", transactionId);
        PhotonResult photonResult = checkResponse(
                HttpUtil.get(
                        getPhotonConfig().getUrl(getPhotonConfig().getPagingTransactionUrl()),
                        param,
                        getGetAptHeader(),
                        HttpUtil.createBody()
                ),
                true
        );
        List<PageTransactionVo> pageTransactionVoStream = photonResult.dataToListEntity(JSONObject.class).stream().map(it -> {
            PageTransactionVo pageTransactionVo = new PageTransactionVo();
            pageTransactionVo.setTransactionId(it.getString("transactionId"));
            pageTransactionVo.setChannelCardId(it.getString("cardId"));
            pageTransactionVo.setCardNumber(it.getString("cardNo"));
            pageTransactionVo.setTransactionType(it.getString("transactionType"));
            pageTransactionVo.setTransactionStatus(it.getString("status"));
            pageTransactionVo.setTransactionAmount(it.getBigDecimal("transactionAmount"));
            pageTransactionVo.setTransactionCurrency(it.getString("transactionCurrency"));
            pageTransactionVo.setTransactionDate(DateUtil.parse(it.getString("createdAt"), DatePattern.UTC_SIMPLE_PATTERN));
            pageTransactionVo.setMerchantName(it.getString("merchantNameLocation"));
            pageTransactionVo.setMcc(it.getString("mcc"));
            pageTransactionVo.setMerchantCountry(it.getString("merchantLocation"));
            pageTransactionVo.setRemark(it.getString("msg"));
            pageTransactionVo.setBillingAmount(it.getBigDecimal("txnPrincipalChangeAmount"));
            pageTransactionVo.setBillingCurrency(it.getString("txnPrincipalChangeCurrency"));
            pageTransactionVo.setOriginalTransactionId(it.getString("originalTransactionId"));
            pageTransactionVo.setFee(it.getBigDecimal("feeDeductionAmount"));
            pageTransactionVo.setFeeCurrency(it.getString("feeDeductionCurrency"));
            return pageTransactionVo;
        }).toList();
        if (pageTransactionVoStream.isEmpty()) {
            throw new ProgramException("查询交易记录失败");
        }
        return pageTransactionVoStream.get(0);
    }

    @Override
    public PageVo<PageClearingVo> pagingClearing(Integer pageNumber, Integer pageSize, String channelCardId, String transactionType, String status, Date startTime, Date endTime) {
        return null;
    }

    @Override
    public PageVo<PageClearingVo> pagingClearing(Integer pageNumber, Integer pageSize, String transactionType, String status, Date startTime, Date endTime) {
        return null;
    }

    @Override
    public PageClearingVo queryClearing(String transactionId) {
        return null;
    }

    @Override
    public BigDecimal queryAccountBalance() {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("currency", "USD");
        param.put("accountType", "FT10001");
        try {
            PhotonResult photonResult = checkResponse(
                    HttpUtil.get(
                            getPhotonConfig().getUrl(getPhotonConfig().getQueryAccountBalanceUrl()),
                            param,
                            getGetAptHeader(),
                            HttpUtil.createBody()
                    ),
                    true
            );
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            return data.getBigDecimal("realTimeBalance");
        } catch (Exception e) {
            return BigDecimal.ZERO;
        }
    }

    @Override
    public BigDecimal queryAccountBalance(String accountId) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("currency", "USD");
        param.put("accountType", "FT10001");
        param.put("matrixAccount", accountId);

        try {
            PhotonResult photonResult = checkResponse(
                    HttpUtil.get(
                            getPhotonConfig().getUrl(getPhotonConfig().getQueryAccountBalanceUrl()),
                            param,
                            getGetAptHeader(),
                            HttpUtil.createBody()
                    ),
                    true
            );
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            return data.getBigDecimal("realTimeBalance");
        } catch (Exception e) {
            return BigDecimal.ZERO;
        }
    }

    @Override
    public BigDecimal queryCardBalance(String channelCardId) {
        CardInfoVo cardInfoVo = queryCardInfo(channelCardId);
        return cardInfoVo.getBalance();
    }

    @Override
    public String queryCardStatus(String channelCardId) {
        CardInfoVo cardInfoVo = queryCardInfo(channelCardId);
        return cardInfoVo.getCardStatus();
    }

    @Override
    public PageVo<PageOperationLogVo> pagingOperationLog(Integer pageNumber, Integer pageSize, String type, Date startTime, Date endTime) {
        return null;
    }

    @Override
    public PageOperationLogVo queryOperationLog(String requestId) {
        return null;
    }

    @Override
    public CardInfoVo queryCardInfo(String channelCardId) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("cardId", channelCardId);
        try {
            PhotonResult photonResult = checkResponse(
                    HttpUtil.get(
                            getPhotonConfig().getUrl(getPhotonConfig().getQueryCardInfoUrl()),
                            param,
                            getGetAptHeader(),
                            HttpUtil.createBody()
                    ),
                    true
            );
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            CardInfoVo cardInfoVo = new CardInfoVo();
            cardInfoVo.setRequestId(data.getString("cardId"));
            cardInfoVo.setChannelCardId(data.getString("cardId"));
            cardInfoVo.setCardStatus(statusConvert(data.getString("cardStatus")));
            cardInfoVo.setTotalLimit(data.getBigDecimal("totalTransactionLimit"));
            cardInfoVo.setBalance(data.getBigDecimal("availableTransactionLimit"));
            cardInfoVo.setBillingCurrency(data.getString("cardCurrency"));
            cardInfoVo.setCardType(data.getString("cardType"));
            cardInfoVo.setCreateDate(DateUtil.parse(data.getString("createdAt"), DatePattern.UTC_SIMPLE_PATTERN));
            cardInfoVo.setCardSecret(
                    CardSecretVo.builder()
                            .cardNumber(data.getString("cardNo"))
                            .cvv(data.getString("cvv"))
                            .expireDate(data.getString("expirationDate"))
                            .build()
            );
            cardInfoVo.setBrand(data.getString("cardScheme"));
            cardInfoVo.setCardholderId(data.getString("cardholderId"));
            cardInfoVo.setNikeName(data.getString("nickname"));
            return cardInfoVo;
        } catch (Exception e) {
            logger.error("查询卡信息失败", e);
            throw new ProgramException("查询卡信息失败");
        }
    }

    @Override
    public CardSecretVo queryCardSecret(String channelCardId) {
        HashMap<String, Object> param = HttpUtil.createParam();
        param.put("cardId", channelCardId);
        try {
            PhotonResult photonResult = checkResponse(
                    HttpUtil.get(
                            getPhotonConfig().getUrl(getPhotonConfig().getQueryCardSecretUrl()),
                            param,
                            getGetAptHeader(),
                            HttpUtil.createBody()
                    ),
                    true
            );
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            return CardSecretVo.builder()
                    .cardNumber(data.getString("cardNo"))
                    .cvv(data.getString("cvv"))
                    .expireDate(data.getString("expirationDate"))
                    .build();
        } catch (Exception e) {
            logger.error("查询卡信息失败", e);
            throw new ProgramException("查询卡信息失败");
        }
    }

    @Override
    public CardSecretVo queryCardSecret(String channelCardId, String cardNumber, String expireDate) {
        return null;
    }

    @Override
    public String createCardHolder(CreateCardHolderDto createCardHolderDto) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("email", createCardHolderDto.getEmail());
        requestBody.put("firstName", createCardHolderDto.getFirstName());
        requestBody.put("lastName", createCardHolderDto.getLastName());
        requestBody.put("mobilePrefix", createCardHolderDto.getMobilePrefix());
        requestBody.put("mobile", createCardHolderDto.getMobile());
        if (StringUtils.isNotBlank(createCardHolderDto.getAccountId())) {
            requestBody.put("matrixAccount", createCardHolderDto.getAccountId());
        } else {
            if (activeProfile.equals("prod")) {
                requestBody.put("matrixAccount", "MI1952819651775836160");
            }
        }
        requestBody.put("dateOfBirth", createCardHolderDto.getBirthDay());
        requestBody.put("nationalityCountryCode", createCardHolderDto.getCountry());
        requestBody.put("residentialAddress", createCardHolderDto.getAddress());
        requestBody.put("residentialCity", createCardHolderDto.getCity());
        requestBody.put("residentialCountryCode", createCardHolderDto.getCountry());
        requestBody.put("residentialPostalCode", createCardHolderDto.getZipCode());
        requestBody.put("residentialState", createCardHolderDto.getState());
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getCreateCardHolderUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            return data.getString("cardholderId");
        } else {
            throw new ProgramException("创建持卡人失败" + photonResult.getMsg());
        }
    }

    @Override
    public String updateCardHolder(UpdateCardHolderDto updateCardHolderDto) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("email", updateCardHolderDto.getEmail());
        requestBody.put("cardholderId", updateCardHolderDto.getCardholderId());
        requestBody.put("firstName", updateCardHolderDto.getFirstName());

        if (StringUtils.isNotBlank(updateCardHolderDto.getAccountId())) {
            requestBody.put("matrixAccount", updateCardHolderDto.getAccountId());
        } else {
            if (activeProfile.equals("prod")) {
                requestBody.put("matrixAccount", "MI1952819651775836160");
            }
        }
        requestBody.put("lastName", updateCardHolderDto.getLastName());
        requestBody.put("mobilePrefix", updateCardHolderDto.getMobilePrefix());
        requestBody.put("mobile", updateCardHolderDto.getMobile());
        requestBody.put("dateOfBirth", updateCardHolderDto.getBirthDay());
        requestBody.put("nationalityCountryCode", updateCardHolderDto.getCountry());
        requestBody.put("residentialAddress", updateCardHolderDto.getAddress());
        requestBody.put("residentialCity", updateCardHolderDto.getCity());
        requestBody.put("residentialCountryCode", updateCardHolderDto.getCountry());
        requestBody.put("residentialPostalCode", updateCardHolderDto.getZipCode());
        requestBody.put("residentialState", updateCardHolderDto.getState());
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getUpdateCardHolderUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            return data.getString("cardholderId");
        } else {
            throw new ProgramException("修改持卡人失败");
        }
    }

    @Override
    public Boolean transfer(TransferDto transferDto) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("currency", "USD");
        if (activeProfile.equals("prod")) {
            requestBody.put("matrixAccount", "MI1952819651775836160");
        }
        if (StringUtils.isNotBlank(transferDto.getAccountId())) {
            requestBody.put("matrixAccount", transferDto.getAccountId());
        }
        requestBody.put("transferAmount", transferDto.getAmount());
        requestBody.put("transferType", transferDto.getType());
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getTransferUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        return photonResult.hasSuccess();
    }

    @Override
    public String createShareAccount(CreateShareAccountRequest createShareAccountRequest) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("matrixAccountName", createShareAccountRequest.getAccountName());
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getCreateShareAccountUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            return data.getString("matrixAccount");
        } else {
            throw new ProgramException("创建共享账户失败");
        }
    }

    @Override
    public Boolean setTransactionLimit(SetTransactionLimitRequest setTransactionLimitRequest) {
        HashMap<String, Object> requestBody = HttpUtil.createBody();
        requestBody.put("requestId", setTransactionLimitRequest.getRequestId());
        requestBody.put("cardId", setTransactionLimitRequest.getChannelCardId());
        requestBody.put("transactionLimit", setTransactionLimitRequest.getLimit());
        requestBody.put("transactionLimitType", "limited");
        requestBody.put("transactionLimitChangeType", setTransactionLimitRequest.getStatus() ? "increase" : "decrease");
        PhotonResult photonResult = checkResponse(
                HttpUtil.post(
                        getPhotonConfig().getUrl(getPhotonConfig().getWithdrawUrl()),
                        getPostHeader(requestBody),
                        requestBody
                ),
                false
        );
        if (photonResult.hasSuccess()) {
            JSONObject data = photonResult.dataToEntity(JSONObject.class);
            BigDecimal availableTransactionLimit = data.getBigDecimal("availableTransactionLimit");
            BigDecimal totalTransactionLimit = data.getBigDecimal("totalTransactionLimit");
            userCardService.updateUsableQuotaAndTotalLimitByChannelCardId(
                    availableTransactionLimit,
                    totalTransactionLimit,
                    setTransactionLimitRequest.getChannelCardId()
            );
        }
        return cardOrderService.setLimitComplete(
                setTransactionLimitRequest.getRequestId(),
                photonResult.hasSuccess() ? "SUCCESS" : "FAIL"
        );
    }

    private String statusConvert(String status) {
        return switch (status) {
            case "normal" -> CardStatusEnum.ACTIVE.getCode();
            case "unactivated" -> CardStatusEnum.INACTIVE.getCode();
            case "freezing", "frozen", "unfreezing" -> CardStatusEnum.BLOCKED.getCode();
            case "risk_frozen", "system_frozen" -> CardStatusEnum.CONTROL.getCode();
            case "expired", "canceling", "cancelled" -> CardStatusEnum.CLOSE.getCode();
            default -> CardStatusEnum.ABNORMAL.getCode();
        };
    }
}
